/*
 *
 *  *    Copyright © OpenAtom Foundation.
 *  *
 *  *    Licensed under the Apache License, Version 2.0 (the "License");
 *  *    you may not use this file except in compliance with the License.
 *  *    You may obtain a copy of the License at
 *  *
 *  *         http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  *    Unless required by applicable law or agreed to in writing, software
 *  *    distributed under the License is distributed on an "AS IS" BASIS,
 *  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  *    See the License for the specific language governing permissions and
 *  *    limitations under the License.
 *
 */

package com.inspur.edp.cef.engine.core.data;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.engine.core.common.CefDataTypeUtil;
import com.inspur.edp.cef.engine.core.exception.CefEngineCoreException;
import com.inspur.edp.cef.engine.core.exception.ErrorCodes;
import com.inspur.edp.cef.entity.entity.ICefData;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class EngineValueObjData extends
    com.inspur.edp.cef.core.data.ValueObjDataBase implements Cloneable {

  private final IGspCommonDataType node;
  private HashMap<String, Object> values;

  public EngineValueObjData(IGspCommonDataType node) {
    Objects.requireNonNull(node, "node");
    this.node = node;
  }

  @JsonIgnore
  protected IGspCommonDataType getDataType(){
    return node;
  }

  @Override
  public Object innerGetValue(String labelId) {
    IGspCommonField element = CefDataTypeUtil
        .checkElementExists(node, labelId, getElementPredicate());
    if (!element.getIsRefElement()) {
      return getValues().get(labelId);
    } else {
      //TODO: udt上的关联暂不支持
      throw new CefEngineCoreException(ErrorCodes.CEF_ENGINE_0007);
//      String parentLabelId = element.getParentAssociation().getBelongElement().getLabelID();
//      Object parentValue = getValues().get(parentLabelId);
//      if (parentValue == null) {
//        return null;
//      } else {
//        return ((AssociationInfo) parentValue).getValue(labelId);
//      }
    }
  }

  private HashMap<String, Object> getValues() {
    if (values == null) {
      values = new HashMap<>(node.getContainElements().size());
    }
    return values;
  }

  @Override
  public ICefData innerCopySelf() {
    try {
      EngineValueObjData result = (EngineValueObjData) this.clone();
      //result.values = CefDataTypeUtil.cloneForValues(this.values);
      return result;
    } catch (CloneNotSupportedException e) {
      throw new CefEngineCoreException(e);
    }
  }

  @Override
  public ICefData innerCopy() {
    try {
      EngineValueObjData result = (EngineValueObjData) this.clone();
      return result;
    } catch (CloneNotSupportedException e) {
      throw new CefEngineCoreException(e);
    }
  }

  private List<String> propertyNames;
  @Override
  public List<String> innerGetPropertyNames() {
    if (propertyNames == null && node.getContainElements() != null) {
      Stream<IGspCommonField> stream = node.getContainElements().stream();
      Predicate<IGspCommonField> predicate = getElementPredicate();
      if (predicate != null) {
        stream = stream.filter(predicate);
      }
      propertyNames = stream.map(item -> item.getLabelID()).collect(Collectors.toList());
    }
    return propertyNames;
  }

  @Override
  public void innerSetValue(String s, Object o) {
    CefDataTypeUtil.checkElementValue(node, s, o, getElementPredicate());
    getValues().put(s, o);
  }

  //#region virtual
  //TODO: 不需要支持运行时定制
  private Predicate<IGspCommonField> getElementPredicate() {
    return null;
  }

  private Predicate<IGspCommonDataType> getNodePredicate() {
    return null;
  }
  //#endregion
}
